import tkinter as tk
import tkinter.ttk as ttk
from modData import modData
from tkinter import messagebox,StringVar
import json,copy,os

class viewRender():
    #用来定位相关文件路径的一个独立窗口
    staticmethod
    def config_view(root):
        def save():
            mp=entry_modpath.get()
            gp=entry_gamepath.get()
            if os.path.exists(mp) and os.path.exists(gp):
                root.db['modPath']=mp
                root.db['gamePath']=gp
                config.destroy()
                root.Go(mp,gp)


        config = tk.Toplevel(root)
        config.geometry("512x512+450+450")
        config.title(f"路径配置") 

        label_modpath= tk.Label(config,text="MOD存放路径")
        label_modpath.grid(row=0,column=0)

        entry_modpath= tk.Entry(config) 
        entry_modpath.grid(row=1,column=0)            

        label_gamepath= tk.Label(config,text="游戏安装路径")
        label_gamepath.grid(row=2,column=0)

        entry_gamepath= tk.Entry(config) 
        entry_gamepath.grid(row=3,column=0)
        
        btn_save=tk.Button(config,text="保存",command=save)
        btn_save.grid(row=4,column=0)

        def on_close():
            messagebox.showerror("警告","没有正确配置目录，程序将退出")
            root.shutdown()

        config.protocol("WM_DELETE_WINDOW",lambda: on_close())


    def __init__(self,ctx) -> None:
        #获取上下文，创建主界面
        self.ctx=ctx
        self.dt=ctx.dt
        self.main_view()

    def window_render(self,type,parent,geometry,title):
        result=None
        if type=="window":
            result=tk.Toplevel(parent)
            result.geometry(geometry)
            result.title(title)       
        return result

    def list_in_window(self,values,parent,title):
        '''当某些值无法在源frame中编辑时，新开窗口进行处理'''
        child_window=self.window_render('window',parent,"768x768+350+350",title)

        def on_change(event,idx,jsonData=None):#暂时不定义保存，直接修改                
            if jsonData!=None:
                values[idx]={"value":json.dumps(jsonData)}
                print('尝试从json获取数据并保存')
            else:
                values[idx]={"value":event.widget.get()} 
        def renderlist():
            #新建一个frame，根据数据类型进行渲染
            frame_1=tk.Frame(child_window)
            frame_1.grid(row=0,column=0,sticky='w')
            entries={};row=0;col=0;col_max=3  
            idx=0
            for t in values:
                if col ==col_max:col=0;row+=2
                key = values.index(t)
                lable_child=tk.Label(frame_1,text=f"value[{key}]")
                lable_child.grid(row=row,column=col,sticky='w')    
                if not '{' in t['value']:
                    dt=StringVar()
                    dt.set('')
                    dt.set(t['value'])
                    modentry = tk.Entry(frame_1,textvariable=dt) 
                    entries[str(t)]=modentry
                    modentry.grid(row=row+1,column=col,sticky='w')
                    #绑定事件，当编辑框修改时将数据实时写入args
                    modentry.bind("<KeyRelease>",lambda event,key=key:on_change(event,key))
                else:          
                    def save(obj,idx):
                        values[idx]={'value': json.dumps(obj)}
                        renderlist()
                    frame_1.save=save
                    btn_detail=tk.Button(frame_1,text=f"编辑详情",command=lambda obj=values[idx]['value'],idx=idx:self.modobj_in_window(obj,frame_1,True,idx,'reward'))
                    btn_detail.grid(row=row+1,column=col,sticky='w')
                row+=2     
                idx+=1  
        renderlist()     
            
    def values_in_window(self,root,title,values,idx=0):
        '''当某些值无法在源frame中编辑时，新开窗口进行处理'''        
        child_window=self.window_render('window',root,"768x768+350+350",title) 
        #新建一个frame，根据数据类型进行渲染
        frame_1=tk.Frame(child_window)
        frame_1.grid(row=0,column=0,sticky='w')
        self.values_in_frame(frame_1,values)
    
    def values_in_frame(self,frame,target):
        entries={};row=0;col=0;col_max=3             
        def on_change(event,key):#暂时不定义保存，直接修改
            target[key]={"value":event.widget.get()}
        def call_new_window(obj,frame,key):
            #分支改到了这里，编辑详情时有可能时带有分组的大数据包（比如function），也有可能是8个value组成的数组，还有可能是json
            #之前是使用了values_in_window方式处理的，此处是否还可以应用
            if type(obj)==dict:
                # obj['info']=key
                if not 'items' in obj:
                    self.values_in_window(frame,key,obj)
                else:
                    self.modobj_in_window(obj,frame,False,0,key)
            if type(obj)==list:
                self.list_in_window(obj,frame,key)

        for t in target:
            if col ==col_max:col=0;row+=2      
            lable_child=tk.Label(frame,text=t)
            lable_child.grid(row=row,column=col,sticky='w')
            if 'value' in target[t] and t!="values":          
                dt=StringVar()
                dt.set(target[t]['value'])
                modentry = tk.Entry(frame,textvariable=dt) 
                entries[t]=modentry
                modentry.grid(row=row+1,column=col,sticky='w')
                #绑定事件，当编辑框修改时将数据实时写入args
                modentry.bind("<KeyRelease>",lambda event,key=t:on_change(event,key))
            else:
                btn_detail=tk.Button(frame,text=f"编辑详情",command=lambda key=t,v=target[t],:call_new_window(v,frame,key))
                btn_detail.grid(row=row+1,column=col,sticky='w')
            col+=1

    def modobj_in_window(self,obj,parent,jsontype=False,idx=0,info=""):
       
        def obj_new():
            '''
            新增项目面临巨大问题
            1、id不能冲突，而该数据结构比较难遍历已有id，也就是说很难防止冲突
            2、由于界面是复用的，创建不同对象，需要渲染不同的界面目前可能涉及的对象
                dramadialogue
                option
                condition
                。。。                                 
            
            '''            
            if info=='dramaDialogue':
                res=self.dt.dialogueMake(obj_window.group_name)
                obj['items'].append(res)
                group_select()
                return
            if info=='function':
                res= self.dt.functionMake(obj_window.group_name)
                obj['items'].append(res)
                group_select()
                return
            
            messagebox.showerror("待开发","目前还不支持")

        def obj_copy(index):
            obj_source=get_target(index)
            obj_new=self.dt.modCopy(obj_source,info)
            obj['items'].append(obj_new)
            group_select()

        def get_target(index):
            objid = list_obj.get(index)
            t = list(filter(lambda x:x['id']['value']==objid,obj['items']))
            return t[0]

        def obj_remove(index):
            #这个也需要考虑组的问题
            target=get_target(index)
            realidx= obj['items'].index(target)
            obj['items'].pop(realidx)
            group_select()

        def popup_menu(event):
            # 获取鼠标所在的列表框项
            index = list_obj.nearest(event.y)
            # 清除先前选择的任何项
            list_obj.selection_clear(0, tk.END)
            # 选择新的项
            list_obj.selection_set(index)
            # 创建右键菜单
            menu = tk.Menu(list_obj, tearoff=0)
            # 清空右键菜单的选项
            menu.delete(0, tk.END)
            menu.add_command(label='复制',command=lambda x=index:obj_copy(x))
            # menu.add_command(label='粘贴')
            menu.add_separator()
            menu.add_command(label='删除',command=lambda x=index:obj_remove(x))
            menu.post(event.x_root, event.y_root)

        #双击列表可以选择分组
        def group_select():            
            idx=list_group.curselection()
            if idx==():
                obj_window.group_name=""
            else:
                selected= idx[0]
                if selected==0:
                    obj_window.group_name=""
                else:
                    obj_window.group_name=obj['groupName'][selected-1]
            list_obj.delete(0,tk.END)
            current_data= list(filter(lambda x:x['tagClassName']['value']==obj_window.group_name,obj['items']))      
            for data in current_data:
                id=data['id']['value']
                list_obj.insert(tk.END,id)
            if len(current_data)>0:
                obj_select()

        #双击数据列表可以选择具体的数据渲染到frame_value
        def obj_select():
            idx=list_obj.curselection()
            if idx==():
                idx=0
            else:
                idx=idx[0]        
            current_data= list(filter(lambda x:x['tagClassName']['value']==obj_window.group_name,obj['items']))      
            self.values_in_frame(frame_value,current_data[idx])

        #当前无法完成json的保存
        def on_mod_window_close(obj):
            if jsontype:
                parent.save(obj,idx)
            obj_window.destroy()

        if jsontype:
            obj=json.loads(obj)
        
        obj_window=self.window_render('window',parent,"768x512+250+150",f"详情编辑:{info}") 
        obj_window.group_name=""
        obj_window.protocol("WM_DELETE_WINDOW",lambda obj=obj: on_mod_window_close(obj))

        frame_group=tk.Frame(obj_window,width=350,height=512)
        frame_group.place(relx=0,rely=0)

        list_group=tk.Listbox(frame_group,width=10,height=20)
        list_group.grid(row=0,column=0,sticky='n', padx=5, pady=5)

        frame_value =tk.Frame(frame_group,width=350,height=512)
        frame_value.grid(row=0,column=2,sticky='n', padx=5, pady=5)
        #暂时不能新增组
        btn_group_new=tk.Button(frame_group,text="新增")
        # btn_group_new.grid(row=1,column=0,sticky='n', padx=5, pady=5)

        list_group.insert(tk.END,"default")  
        list_obj=tk.Listbox(frame_group,width=15,height=20)
        list_obj.grid(row=0,column=1,sticky='n', padx=5, pady=5) 

        btn_obj_new=tk.Button(frame_group,text="新增",command=lambda:obj_new())
        btn_obj_new.grid(row=1,column=1,sticky='n', padx=5, pady=5)

        for i in obj['groupName']:
            list_group.insert(tk.END,i)

        # 绑定右键菜单
        list_obj.bind('<Button-3>', lambda e :popup_menu(e))
        #分组标签是通过具体对象的 tagClassName['value']来进行标注的，如果没有标签则为''
        list_group.bind("<Double-Button-1>",lambda e:group_select())
        list_obj.bind("<Double-Button-1>",lambda e:obj_select())

        group_select()

    #正式加载mod，允许同时打开多个
    def mod_in_window(self,obj):
        #mod路径
        pathroot=obj['path']
        new_mod_window=self.window_render('window',self.ctx,"768x512+250+150",f"MOD编辑【{pathroot}】")  

        #关闭该窗口时解锁主界面的配置，否则禁止同时打开两次，避免数据异常
        def on_mod_window_close(obj):
            idx = self.mod_opened.index(obj['soleID'])
            self.mod_opened.pop(idx)           
            new_mod_window.destroy()

        #点击保存触发的事件
        def onSave():
            data =new_mod_window.md
            self.dt.modSave(pathroot,data)

        #绑定窗口关闭事件
        new_mod_window.protocol("WM_DELETE_WINDOW",lambda: on_mod_window_close(obj))     

        #读取MOD信息
        new_mod_window.md=self.dt.modRead(pathroot)

        new_mod_window.data=obj

        #创建框架，用来渲染主要mod对象，配置列宽，渲染位置
        frame_obj=tk.Frame(new_mod_window,width=512,height=384)
        frame_obj.columnconfigure(0, minsize=200)
        frame_obj.columnconfigure(1, minsize=200)
        frame_obj.columnconfigure(2, minsize=200)
        frame_obj.place(relx=0.5,rely=0.2,anchor="center")

        #一个简易的mod信息存放框架
        frame_info=tk.Frame(new_mod_window)
        frame_info.place(relx=0.5,rely=0.8,anchor='center')

        #保存按钮
        btn_save = tk.Button(new_mod_window,text="保存",command=onSave)
        btn_save.place(relx=0.9,rely=0.9)

        #遍历mod中的主对象，并绑定按钮，单击时加载其数据到列表
        row=0;col=0;maxcol=3        
        for i in new_mod_window.md:
            obj_m=new_mod_window.md[i] 
            if col>= maxcol:
                row+=1
                col=0      
            #分别针对大对象创建编辑按钮，每个大对象都是一个字典，有个字列表为itmes，计算下数量显示在按钮上
            if type(obj_m) == dict:
                count=len(obj_m['items'])
                # obj_m['info']=i
                btn=tk.Button(frame_obj,text=f"{i}({count})",width=25,command=lambda obj=obj_m,key=i:self.modobj_in_window(obj,new_mod_window,False,info=key))          
                btn.grid(row=row,column=col,sticky='w')                
            #有两个信息绑定到frame_info框架中
            else:
                label1=tk.Label(frame_info,text=f"{i}:【{obj_m}】")
                label1.grid(row=row,column=col,sticky='w')
            col+=1

    '''渲染主界面的函数'''
    def main_view(self):
        self.mod_opened=[]
        title_label = tk.Label(self.ctx, text="鬼谷八荒MOD制作辅助工具！！")
        title_label.grid(row=0, column=1, sticky="w")  # 左对齐        

        #加载mod列表，并且绑定相关事件可以双击之后在新窗口渲染mod详情
        frame1=tk.Frame(self.ctx)
        frame1.grid(row=1,column=0,sticky='w',pady=10)
        frame2=tk.Frame(self.ctx)
        frame2.grid(row=2,column=0,sticky='w',pady=10)

        list_mod=tk.Listbox(frame2)
        list_mod.grid(row=2, column=0, columnspan=2, padx=0, pady=0, sticky="nsew")

        for i in self.ctx.db['storage']:list_mod.insert(tk.END,i['name'])  

        def on_doubleclick(idx):#双击列表项定位mod信息
            mod = self.ctx.db['storage'][idx[0]]
            if not mod['soleID'] in self.mod_opened:
                self.mod_opened.append(mod['soleID'])
                self.mod_in_window(mod)
            else:messagebox.showwarning("重复","mod已经打开，请勿重复开启")
            
        #双击直接进入编辑页面
        list_mod.bind("<Double-Button-1>",lambda e=None :on_doubleclick(list_mod.curselection()))   
